package commons.reflect.examples;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;

public class ObjectAnalyzer {
    private ArrayList<Object> visited = new ArrayList<>();
    
    public String toString(Object obj) throws IllegalAccessException {
        if (obj == null) {
            return "null";
        }
        if (visited.contains(obj)) {
            return "...";
        }
        Class clazz = obj.getClass();
        if (clazz == String.class) {
            return (String) obj;
        }
        if (clazz.isArray()) {
            StringBuilder builder = new StringBuilder();
            builder.append(clazz.getComponentType()).append("[] {");
            for (int i = 0; i < Array.getLength(obj); i++) {
                if (i > 0) builder.append(", ");
                Object val = Array.get(obj, i);
                if (clazz.getComponentType().isPrimitive()) {
                    builder.append(val);
                } else {
                    builder.append(toString(val));
                }
            }
            builder.append("}");
            return builder.toString();
        }
        //inspace the filelds of this class and all superclasses
        String r = clazz.getName();
        do {
            r += "[";
            Field[] filelds = clazz.getDeclaredFields();
            AccessibleObject.setAccessible(filelds, true);
            for (Field f : filelds) {
                if (!Modifier.isStatic(f.getModifiers())) {
                    if (!r.endsWith("[")) r += ",";
                    r += f.getName() + "=";
                    Class t = f.getType();
                    Object val = f.get(obj);
                    if (t.isPrimitive()) {
                        r += val;
                    } else {
                        r += toString(val);
                    }
                }
            }
            r += "]";
            clazz = clazz.getSuperclass();
        } while(clazz != null);
        return r;
    }
}
